#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/time.h>

// 缓冲区大小: 256 MB
#define BUFFER_SIZE (256 * 1024 * 1024)
#define FILE_NAME "temp_speed_test_file.dat"
#define NUM_RUNS 5 // 从10次减少到5次以便快速测试；实验要求10次

double get_time_sec() {
    struct timeval tv;
    gettimeofday(&tv, NULL);
    return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0;
}

int main() {
    char *buffer;
    int fd;
    double start_time, end_time, duration;
    double total_write_speed = 0, total_read_speed = 0;
    double write_speeds[NUM_RUNS], read_speeds[NUM_RUNS];
    ssize_t bytes_written, bytes_read;

    // 分配缓冲区
    buffer = (char *)malloc(BUFFER_SIZE);
    if (buffer == NULL) {
        perror("错误：分配缓冲区失败");
        return 1;
    }
    // 用一些数据填充缓冲区 (可选，但对实际写入有好处)
    memset(buffer, 'A', BUFFER_SIZE);

    printf("缓冲区大小: %.2f MB\n", (double)BUFFER_SIZE / (1024 * 1024));
    printf("运行次数: %d\n\n", NUM_RUNS);

    // --- 写测试 ---
    printf("--- 写测试 ---\n");
    for (int i = 0; i < NUM_RUNS; i++) {
        // O_DSYNC 确保数据写入磁盘，而不仅仅是内核缓冲区。
        // 这能得到更真实的磁盘速度，但可能会慢一些。
        // 对于简单测试，O_WRONLY | O_CREAT | O_TRUNC 也可以。
        fd = open(FILE_NAME, O_WRONLY | O_CREAT | O_TRUNC | O_DSYNC, 0644);
        if (fd < 0) {
            perror("错误：打开文件进行写入失败");
            free(buffer);
            return 1;
        }

        start_time = get_time_sec();
        bytes_written = write(fd, buffer, BUFFER_SIZE);
        // fsync(fd); // O_DSYNC 的替代方案，在 write 之后调用
        end_time = get_time_sec();

        close(fd);

        if (bytes_written < 0) {
            perror("文件写入错误");
            free(buffer);
            return 1;
        }
        if (bytes_written < BUFFER_SIZE) {
            fprintf(stderr, "部分写入: 写入 %zd 字节，期望 %d 字节\n", bytes_written, BUFFER_SIZE);
        }

        duration = end_time - start_time;
        if (duration > 0) {
            write_speeds[i] = (double)bytes_written / (1024 * 1024) / duration; // MB/s
            printf("第 %d 次运行: 写入 %.2f MB 用时 %.4f 秒, 速度: %.2f MB/s\n",
                   i + 1, (double)bytes_written / (1024 * 1024), duration, write_speeds[i]);
            total_write_speed += write_speeds[i];
        } else {
            write_speeds[i] = 0; // 避免除以零 (如果速度太快)
            printf("第 %d 次运行: 时间太短，无法准确测量写入速度。\n", i + 1);
        }
    }
    double avg_write_speed = total_write_speed / NUM_RUNS;
    printf("平均写入速度: %.2f MB/s\n\n", avg_write_speed);


    // --- 读测试 ---
    // 将使用上一次写测试创建的文件。
    // 为了更准确地测试读取，如果有 sudo 权限，可以清除 OS 缓存:
    // sudo sh -c 'echo 3 > /proc/sys/vm/drop_caches'
    // 这在基础实验中通常不做。
    printf("--- 读测试 (读取上次写入的文件) ---\n");
    for (int i = 0; i < NUM_RUNS; i++) {
        // 为确保测试的是磁盘 I/O 而非缓存，可以使用 O_DIRECT。
        // 但 O_DIRECT 对缓冲区和 I/O 大小有对齐要求。
        // 为简单起见，此处不使用 O_DIRECT。
        fd = open(FILE_NAME, O_RDONLY);
        if (fd < 0) {
            perror("错误：打开文件进行读取失败");
            free(buffer);
            return 1;
        }

        start_time = get_time_sec();
        // 将整个文件内容读入缓冲区
        // 循环以确保在 read() 返回小于请求值时读取所有数据
        ssize_t total_bytes_read_this_run = 0;
        ssize_t current_read;
        while(total_bytes_read_this_run < BUFFER_SIZE) {
            current_read = read(fd, buffer + total_bytes_read_this_run, BUFFER_SIZE - total_bytes_read_this_run);
            if(current_read < 0) {
                perror("文件读取错误");
                close(fd);
                free(buffer);
                return 1;
            }
            if(current_read == 0) { // 文件结束 (EOF)
                break;
            }
            total_bytes_read_this_run += current_read;
        }
        bytes_read = total_bytes_read_this_run;
        end_time = get_time_sec();
        close(fd);

        duration = end_time - start_time;
        if (duration > 0) {
            read_speeds[i] = (double)bytes_read / (1024 * 1024) / duration; // MB/s
            printf("第 %d 次运行: 读取 %.2f MB 用时 %.4f 秒, 速度: %.2f MB/s\n",
                   i + 1, (double)bytes_read / (1024 * 1024), duration, read_speeds[i]);
            total_read_speed += read_speeds[i];
        } else {
            read_speeds[i] = 0;
            printf("第 %d 次运行: 时间太短，无法准确测量读取速度。\n", i + 1);
        }
    }
    double avg_read_speed = total_read_speed / NUM_RUNS;
    printf("平均读取速度: %.2f MB/s\n\n", avg_read_speed);

    // 计算方差 (可选, 根据实验文本: "和方差方式")
    double sum_sq_diff_write = 0, sum_sq_diff_read = 0;
    for(int i=0; i<NUM_RUNS; ++i) {
        sum_sq_diff_write += (write_speeds[i] - avg_write_speed) * (write_speeds[i] - avg_write_speed);
        sum_sq_diff_read += (read_speeds[i] - avg_read_speed) * (read_speeds[i] - avg_read_speed);
    }
    // 样本方差 (n-1)
    double variance_write = (NUM_RUNS > 1) ? sum_sq_diff_write / (NUM_RUNS -1) : 0;
    double variance_read = (NUM_RUNS > 1) ? sum_sq_diff_read / (NUM_RUNS -1) : 0;

    printf("写入速度方差: %.2f (MB/s)^2\n", variance_write);
    printf("读取速度方差: %.2f (MB/s)^2\n", variance_read);

    // 清理
    free(buffer);
    if (remove(FILE_NAME) != 0) {
        perror("错误：删除临时文件失败");
    }

    return 0;
}